home *** CD-ROM | disk | FTP | other *** search
- /*
- FILE: aiff.c
- PROJECT: Ford grant DSP
- AUTHOR: Ben Denckla
- COMMENT: generalized code for AIFF-based DSP; contains main()
- LINKAGE: interface.c, MacTraps, SANE, ANSI, and a file with
- the "programmer-user variables and functions" listed in aiff.h.
- */
-
- #include "aiff.h"
- #include "interface.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <console.h>
- #include <math.h> // must come before SANE #include to have precedence
- #include <SANE.h>
-
- #define BUF_SIZ (1L << 14) // buffer size, in frames
-
- #define ODDPAD(x) ( (x) + ((x) & 1) ) // rounds up to nearest even #
- // needed because if chunk size is odd, there is an uncounted zero pad byte
-
- #define FREAD( dat ) fread( &(dat), sizeof (dat), 1, inf )
- #define MIN( a, b ) ((a) < (b) ? (a) : (b))
-
- #define SAMDAT( action, file ) \
- if (!f##action ( d, ph.framsiz*buflen, 1, file )) \
- err( #action"ing sample data" )
-
- basicaiffbeg ba;
- privateheader ph;
- void *d; // audio data buffer
-
- static FILE *inf, *ouf; // input and output files
- static basicaiffbeg init = {
- {'FORM', 46}, // [frmhd.id], frmhd.si (1,2)
- 'AIFF', // [frm]
- {'COMM', 18}, // [comhd.id], [comhd.si]
- {0}, // com.chan, com.fram, com.wdsi, com.rate
- {'SSND', 8}, // [sndhd.id], sndhd.si (1)
- {0} // snd.offs, snd.bksi
- };
- /*
- 1. frmhd.si and sndhd.si are initialized to their values assuming a sample
- length of zero bytes. This way, when the sample length in bytes is
- known, it can just be added to the default values, perhaps adding one
- to frmhd.si (if sndhd.si is odd).
- 2. The square brackets around identifiers like "frmhd.id" indicate that
- this field does not change.
- */
-
- void err ( char *errmsg ) {
- fprintf( stderr, "FATAL ERROR: %s.\n", errmsg);
- exit(0);
- }
-
- void warn ( char *warnmsg ) {
- fprintf( stderr, "WARNING: %s.\n", warnmsg);
- }
-
- DEFFUNC( void open_inf( void ) ) {
- char infstr[256];
- Point where = { 64, 64 };
- SFTypeList types = { 'AIFF' };
-
- if ( getfullfstr( where, 1, types, infstr ) )
- err( "getting input file name" );
- if ( !(inf = fopen( infstr, "rb" )) ) err( "opening input file" );
- }
-
- DEFFUNC( void open_ouf( void ) ) {
- long tmp_ftype;
- Point where = { 64, 64 };
- char oufstr[256] = "Untitled";
-
- if ( putfullfstr( where, "Save AIFF file to:", oufstr ) )
- err( "getting output file name" );
- tmp_ftype = _ftype; // save _ftype
- _ftype = 'AIFF';
- if ( !( ouf = fopen( oufstr, "wb" ) ) ) err( "opening output file" );
- _ftype = tmp_ftype; // restore _ftype
- }
-
- DEFFUNC( void process_com( ckhd hd ) ) {
- // processes information in COMM chunk
- if ( hd.si != init.comhd.si ) warn( "wrong COMM chunk header size" );
- if ( !FREAD( ba.com ) ) err( "reading COMM chunk body" );
- x80tox96( &(ba.com.rate), &(ph.rate) ); // convert float formats
- ph.framsiz = ( (ba.com.wdsi+7) / 8 ) * ba.com.chan;
- printf(
- "\tsampling rate (frames/sec): %f\n"
- "\tword size (bits): %hd\n"
- "\tchannels: %hd\n"
- "\tframe size (bytes): %lu (calculated, not in file)\n"
- "\tsample frames: %lu\n",
- ph.rate, ba.com.wdsi, ba.com.chan, ph.framsiz, ba.com.fram );
- }
-
- DEFFUNC( void process_snd( ckhd hd ) ) {
- // prints information in SSND chunk, seeks past sample data
-
- ba.sndhd.si = hd.si;
- if ( !FREAD( ba.snd ) ) err( "reading SSND chunk body" );
- printf( "\toffset: %lu block size: %lu\n", ba.snd.offs, ba.snd.bksi );
- if ( ba.snd.bksi )
- puts( "blocksize and offset not supported by this program" );
- ph.samdatpos = ftell( inf );
- if ( fseek( inf, ODDPAD(ba.sndhd.si) - init.sndhd.si , SEEK_CUR) )
- err( "seeking past sample data");
- }
-
- DEFFUNC( void process_txt( ckhd hd ) ) {
- // prints information in a text chunk
- #define TXTBUF_SIZ 80
- char s[TXTBUF_SIZ];
- int txtbufpos, txtbuflen;
-
- hd.si = ODDPAD(hd.si); // OK to include zero pad as part of string in C
- printf( "\ttext: \"" );
- for (txtbufpos = 0; txtbufpos < hd.si; txtbufpos += txtbuflen) {
- txtbuflen = MIN( hd.si - txtbufpos, TXTBUF_SIZ );
- if ( !fread( s, txtbuflen, 1, inf ) ) err( "reading text chunk" );
- printf( "%.*s", txtbuflen, s );
- }
- puts ( "\"" );
- }
-
- DEFFUNC( void process_ckhd( ckhd hd ) ) {
- char *idstr, i;
-
- printf("\nFound '%.4s' chunk of size %ld\n", &hd.id, hd.si );
- idstr = (char *) &(hd.id);
- for (i=0; i<4; i++)
- if ( idstr[i] < ' ' || idstr[i] > '~' ) {
- warn( "Forbidden character in ID" );
- }
- if ( idstr[0] == ' ' ) warn( "Forbidden leading space in ID" );
- }
-
- DEFFUNC( void scan_inf ( void ) ) {
- // scans inf, reading in essential header data & finding sample data
- // position (does not actually read sample data)
- int comfound = 0, sndfound = 0, fread_res;
- ckhd hd; long frmck_endpos;
-
- if ( !FREAD( ba.frmhd ) || !FREAD( ba.frm ) )
- err( "reading FORM header or type" );
- process_ckhd( ba.frmhd );
- if ( ba.frmhd.id != init.frmhd.id || ba.frm != init.frm ) {
- warn( "Bad FORM chunk id or type" );
- ba.frmhd.id = init.frmhd.id; ba.frm = init.frm;
- }
-
- frmck_endpos = ba.frmhd.si + sizeof hd;
- while ( ftell( inf ) < frmck_endpos ) {
- if ( !FREAD( hd ) ) err( "reading next chunk header" );
-
- process_ckhd( hd );
-
- switch ( hd.id ) {
- case 'COMM': comfound++; process_com( hd ); break;
- case 'SSND': sndfound++; process_snd( hd ); break;
- case 'NAME':
- case 'AUTH':
- case '(c) ':
- case 'ANNO': process_txt( hd ); break;
- default:
- puts( "\tThis chunk type is not supported by this program" );
- if ( fseek( inf, ODDPAD(hd.si), SEEK_CUR ) )
- err( "seeking past unsupported chunk body" );
- }
- }
- puts( "\n" );
-
-
- if ( fgetc( inf ) != EOF ) warn( "File extends beyond FORM chunk" );
- if ( comfound != 1 || sndfound != 1 )
- err( "Not exactly 1 COMM and 1 SSND chunk" );
- if ( ba.com.fram * ph.framsiz != ba.sndhd.si - init.sndhd.si ) {
- warn( "COMM & SSND chunks disagree about sample length" );
- ba.sndhd.si = init.sndhd.si + ba.com.fram * ph.framsiz;
- }
-
- if ( fseek( inf, ph.samdatpos, SEEK_SET ) )
- err( "seeking to beginning of sample data" );
-
- ba.frmhd.si = init.frmhd.si + ODDPAD(ba.com.fram * ph.framsiz);
- }
-
- DEFFUNC( void write_ouf_hd( void ) ) {
- if ( !fwrite( &ba, sizeof ba, 1, ouf ) ) err( "writing to output file" );
- }
-
- DEFFUNC( void prog_report( long bufpos ) ) {
- // updates (& creates, if necessary) a bar graph of progress
- #define BARMAX 75 // length of progress report bar
- char barlen;
- static char oldbarlen = 0, bar[BARMAX];
-
- if (bufpos == 0) {
- fputs( "Processing...\n", stderr );
- memset( bar, '*', BARMAX );
- fprintf( stderr, "%.*s\n", BARMAX, bar );
- }
- else {
- barlen = (double) (bufpos / ba.com.fram) * BARMAX;
- fprintf( stderr, "%.*s", barlen - oldbarlen, bar );
- oldbarlen = barlen;
- if ( bufpos == ba.com.fram ) fputc( '\n', stderr );
- }
- fflush( stderr );
- }
-
- DEFFUNC( void pad( FILE *ouf ) ) {
- if ( (ba.com.fram * ph.framsiz) % 2 )
- if ( fputc( 0, ouf ) == EOF ) err( "padding sample data" );
- }
-
- int main ( int argc, char **argv ) {
- long bufpos, buflen; // 1,2
-
- ccommand( &argv );
- console_options.title = "\pDenckla Ford Grant AIFF DSP";
-
- ba = init;
-
- if ( take_input ) { open_inf(); scan_inf(); }
-
- init_process();
-
- if ( make_output ) { open_ouf(); write_ouf_hd(); }
-
- if (!(d = malloc( ph.framsiz*BUF_SIZ )))
- err( "allocating memory for sample buffer" );
-
- for (bufpos = 0; bufpos < ba.com.fram; bufpos += buflen) {
- prog_report( bufpos );
- buflen = MIN( ba.com.fram - bufpos, BUF_SIZ ) ;
- if ( take_input ) SAMDAT( read, inf );
- process_samdat( buflen );
- if ( make_output ) SAMDAT( write, ouf );
- }
-
- prog_report( bufpos );
-
- if ( make_output ) { pad( ouf ); fclose( ouf ); }
- if ( take_input ) fclose( inf );
- free( d );
-
- term_process();
-
- return 0;
- }
- /*
- 1. buffer position: frame # where the next buffer will begin
- 2. buffer length: # of meaningful frames in the buffer.
- buflen == BUF_SIZ on all passes except for the last, when buflen ==
- samlen % BUF_SIZ.
- The following is an example for bufpos = 4 and buflen = 2.
- (In reality these quantities will be much larger.)
- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | (sample frames)
- |-------| |
- buflen |
- bufpos
- */
-